﻿#pragma once

#include <vulkan/vulkan.hpp>
#include "Render/Scene/PreRenderSceneNodes.h"
#include "Render/Scene/SceneParametersBuffer.h"
#include "Render/Scene/DefferRenderAttachments.h"

class CVulkanViewportWidget;
class CVulkanScene;

class CVulkanPointLight
{
public:
    CVulkanPointLight();
    ~CVulkanPointLight();

    //设置点光源数据
    void SetPointLight(const SPreRenderPointLight& InPointLight);

    //记录生成阴影图的命令
    void RecordShadowMapCommand(vk::CommandBuffer InCmdBuffers, CVulkanScene* InScene);

    //记录延迟着色的命令
    void RecordDefferShadingCommand(
        vk::CommandBuffer InCmdBuffers
        , CVulkanScene* InScene
        ,const SSceneParameters& InParameters 
        ,CDefferRenderAttachments* Attachments
        );

    int32_t LightIndex=-1;
protected:
    //调整阴影图大小，由于默认为0，所以至少要调用一次
    void Resize(uint32_t InWidth, uint32_t InHeight);

    //重新生成描述符,由于描述符池自动重置，所以每帧都要重新生成
    void UpdateDescriptor();

    uint32_t Width=0;
    uint32_t Height=0;
    SPreRenderPointLight RenderData;

    vk::Image Image;
    SVulkanMemoryBlock MemoryBlock;
    vk::ImageView ImageView;

    vk::Image DepthImage;
    SVulkanMemoryBlock DepthMemoryBlock;
    vk::ImageView DepthImageView;

    vk::Framebuffer FrameBuffer;

    //最终生成的阴影图
    vk::Image CubeImage;
    SVulkanMemoryBlock CubeMemoryBlock;
    vk::ImageView CubeImageView;

    //用于渲染阴影贴图的缓冲区 
    std::shared_ptr<TVulkanUniformBuffer<CSceneGlobal::SPointLightShadowMapBuffer>> ShadowMapBuffer[6];
    
    //vulkan cube faces order is +X -X +Y -Y +Z -Z 
    //in GLSL, cube image is calculated in left hand cooridnating, so inversed  +Y and -Y
    enum class ECubicDirection : uint8_t
    {
        Right=0,
        Left=1,
        Forward=3,
        Backward=2,
        Top=4,
        Bottom=5,
    };    
    
    SMatrix4x4 ProjectionMatrix;
    SMatrix4x4 ViewMatrix[6];

    vk::DescriptorSet ShadowMapDescriptorSet[6];
};


//绘制点光源
class CVulkanPointLights
{
public:
    CVulkanPointLights()=default;

    //预处理点光源数据
    //筛选出在视锥体内的点光源
    //并统计描述符数量
    void PreProcess(const TVector<SPreRenderPointLight>& InPointLights,CVulkanViewportWidget* InViewport);

    int64_t GetPointLightNum() const;

    //测试一个球体是否在光照范围内
    bool IsInLightRange(int64_t InLightIndex,const SVec3& InSpherePosition,float InSphereRadius);
protected:

    //剔除后的点光源
    TVector<SPreRenderPointLight> PointLights;


public:
    //记录生成点光源阴影图的命令
    void RecordShadowMapCommand(
        vk::CommandBuffer InCmdBuffers
        ,CVulkanScene* InScene
        );

    //记录延迟着色的命令
    void RecordDefferShadingCommand(
        vk::CommandBuffer InCmdBuffers
        ,CVulkanScene* InScene
        ,const SSceneParameters& InParameters 
        ,CDefferRenderAttachments* Attachments
        
        );

protected:
    //点光源渲染对象，与点光源一一对应
    TVector<CVulkanPointLight> RenderLights;

};